package com.etone.smartAudit.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.etone.smartAudit.domain.Admin;
import com.etone.smartAudit.domain.ServerInfo;
import com.etone.smartAudit.dto.fileOperation.FileMakeDTO;
import com.etone.smartAudit.dto.fileOperation.FileMoveOrCopyDTO;
import com.etone.smartAudit.dto.fileOperation.FileRenameDTO;
import com.etone.smartAudit.dto.fileOperation.compress.CompressDTO;
import com.etone.smartAudit.dto.fileOperation.compress.DecompressDTO;
import com.etone.smartAudit.error.CustomParameterizedException;
import com.etone.smartAudit.utils.SignUtil;
import com.etone.smartAudit.vo.fileOperation.FileVO;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.client.RestTemplate;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author: sovy
 * @date: 2020/11/24
 * @description:
 */
@Service
@Log4j2
public class ServerFileOperationService {

    @Autowired
    private ItemServerPathService itemServerPathService;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private ServerInfoService serverInfoService;

    @Value("${serverFileOperation.key}")
    private String signKey;

    @Value("${serverFileOperation.context-path}")
    private String fileContextPath;

    @Value("${serverFileOperation.port}")
    private Integer filePort;

    /**
     * 获取文件列表
     *
     * @param admin
     * @param itemId
     * @param serverId
     * @param path
     * @return
     */
    public List<FileVO> fileList(Admin admin, Integer itemId, Integer serverId, String path) {
        ServerInfo serverInfo = serverInfoService.get(serverId);
        itemServerPathService.hasAuthThrow(admin, itemId, serverId, path);
        Long timestamp = System.currentTimeMillis();
        String sign = SignUtil.sign(path, timestamp);
        String url = "http://" + serverInfo.getIp() + ":" + filePort + fileContextPath + "/files/list?path=" + path + "&timestamp=" + timestamp + "&sign=" + sign;
        log.info("{}请求文件列表 : {}", admin.getNickName(), url);
        log.info("{}请求文件地址 : {}", admin.getNickName(), path);
        ResponseEntity<String> responseEntity = restTemplate.getForEntity(url, String.class);
        if (responseEntity.getStatusCode().equals(HttpStatus.OK)) {
            String result = responseEntity.getBody();
            List<FileVO> fileVOS = JSONArray.parseArray(result, FileVO.class);
            if (CollectionUtils.isEmpty(fileVOS)) {
                return new ArrayList<>();
            }

            return fileVOS.stream().sorted(Comparator.comparing(FileVO::getName)).sorted(Comparator.comparing(FileVO::getIsFile)).collect(Collectors.toList());
        } else {
            JSONObject jsonObject = JSON.parseObject(responseEntity.getBody());
            throw new CustomParameterizedException(jsonObject.getJSONObject("parameters").getString("message"));
        }
    }

    /**
     * 文件重命名
     *
     * @param admin
     * @param itemId
     * @param serverId
     * @param fileRenameDTO
     */
    public void rename(Admin admin, Integer itemId, Integer serverId, FileRenameDTO fileRenameDTO) {
        ServerInfo serverInfo = serverInfoService.get(serverId);
        itemServerPathService.hasAuthThrow(admin, itemId, serverId, fileRenameDTO.getFilePath());

        Long timestamp = System.currentTimeMillis();
        String sign = SignUtil.sign(fileRenameDTO, timestamp);
        String url = "http://" + serverInfo.getIp() + ":" + filePort + fileContextPath + "/files/rename?timestamp=" + timestamp + "&sign=" + sign;
        log.info("{}请求重命名: {}", admin.getNickName(), url);
        log.info("{}重命名，文件名称:{}，新名称{}", admin.getNickName(), fileRenameDTO.getFilePath(), fileRenameDTO.getNewName());
        try {
            //参数
            RequestEntity<FileRenameDTO> requestEntity = RequestEntity.put(new URI(url)).header("Content-Type", "application/json").body(fileRenameDTO);
            ResponseEntity<String> responseEntity = restTemplate.exchange(requestEntity, String.class);
            if (!responseEntity.getStatusCode().equals(HttpStatus.OK)) {
                JSONObject jsonObject = JSON.parseObject(responseEntity.getBody());
                throw new CustomParameterizedException(jsonObject.getJSONObject("parameters").getString("message"));
            }
        } catch (URISyntaxException e) {
            e.printStackTrace();
            throw new CustomParameterizedException(e.getMessage());
        }

    }

    /**
     * 移动文件
     *
     * @param admin
     * @param itemId
     * @param serverId
     * @param fileMoveOrCopyDTOS
     */
    public void move(Admin admin, Integer itemId, Integer serverId, List<FileMoveOrCopyDTO> fileMoveOrCopyDTOS) {
        ServerInfo serverInfo = serverInfoService.get(serverId);
        fileMoveOrCopyDTOS.forEach(fileMoveOrCopyDTO -> {
            itemServerPathService.hasAuthThrow(admin, itemId, serverId, fileMoveOrCopyDTO.getSourceFile());
        });
        Long timestamp = System.currentTimeMillis();
        String sign = SignUtil.sign(fileMoveOrCopyDTOS, timestamp);
        String url = "http://" + serverInfo.getIp() + ":" + filePort + fileContextPath + "/files/move?timestamp=" + timestamp + "&sign=" + sign;
        log.info("{}请求移动文件: {}", admin.getNickName(), url);
        fileMoveOrCopyDTOS.forEach(fileMoveOrCopyDTO -> {
            log.info("{}请求移动,源文件{},目标文件{},是否覆盖{}", admin.getNickName(), fileMoveOrCopyDTO.getSourceFile(), fileMoveOrCopyDTO.getDestFile(), fileMoveOrCopyDTO.getIsReplace());
        });
        try {
            //参数
            RequestEntity<List<FileMoveOrCopyDTO>> requestEntity = RequestEntity.put(new URI(url)).header("Content-Type", "application/json").body(fileMoveOrCopyDTOS);
            ResponseEntity<String> responseEntity = restTemplate.exchange(requestEntity, String.class);
            if (!responseEntity.getStatusCode().equals(HttpStatus.OK)) {
                JSONObject jsonObject = JSON.parseObject(responseEntity.getBody());
                throw new CustomParameterizedException(jsonObject.getJSONObject("parameters").getString("message"));
            }
        } catch (URISyntaxException e) {
            e.printStackTrace();
            throw new CustomParameterizedException(e.getMessage());
        }

    }

    /**
     * 复制文件
     *
     * @param admin
     * @param itemId
     * @param serverId
     * @param fileMoveOrCopyDTOS
     */
    public void copy(Admin admin, Integer itemId, Integer serverId, List<FileMoveOrCopyDTO> fileMoveOrCopyDTOS) {
        ServerInfo serverInfo = serverInfoService.get(serverId);
        fileMoveOrCopyDTOS.forEach(fileMoveOrCopyDTO -> {
            itemServerPathService.hasAuthThrow(admin, itemId, serverId, fileMoveOrCopyDTO.getSourceFile());
        });
        Long timestamp = System.currentTimeMillis();
        String sign = SignUtil.sign(fileMoveOrCopyDTOS, timestamp);
        String url = "http://" + serverInfo.getIp() + ":" + filePort + fileContextPath + "/files/copy?timestamp=" + timestamp + "&sign=" + sign;
        log.info("{}请求复制文件: {}", admin.getNickName(), url);
        fileMoveOrCopyDTOS.forEach(fileMoveOrCopyDTO -> {
            log.info("{}请求复制,源文件{},目标文件{},是否覆盖{}", admin.getNickName(), fileMoveOrCopyDTO.getSourceFile(), fileMoveOrCopyDTO.getDestFile(), fileMoveOrCopyDTO.getIsReplace());
        });
        try {
            //参数
            RequestEntity<List<FileMoveOrCopyDTO>> requestEntity = RequestEntity.put(new URI(url)).header("Content-Type", "application/json").body(fileMoveOrCopyDTOS);
            ResponseEntity<String> responseEntity = restTemplate.exchange(requestEntity, String.class);
            if (!responseEntity.getStatusCode().equals(HttpStatus.OK)) {
                JSONObject jsonObject = JSON.parseObject(responseEntity.getBody());
                throw new CustomParameterizedException(jsonObject.getJSONObject("parameters").getString("message"));
            }
        } catch (URISyntaxException e) {
            e.printStackTrace();
            throw new CustomParameterizedException(e.getMessage());
        }

    }

    /**
     * 删除文件
     *
     * @param admin
     * @param itemId
     * @param serverId
     * @param files
     */
    public void delete(Admin admin, Integer itemId, Integer serverId, List<String> files) {
        ServerInfo serverInfo = serverInfoService.get(serverId);
        files.forEach(path -> {
            itemServerPathService.hasAuthThrow(admin, itemId, serverId, path);
        });

        Long timestamp = System.currentTimeMillis();
        String sign = SignUtil.sign(files, timestamp);
        String deleteFileStr = files.stream().collect(Collectors.joining(","));
        String url = "http://" + serverInfo.getIp() + ":" + filePort + fileContextPath + "/files/delete?files=" + deleteFileStr + "&timestamp=" + timestamp + "&sign=" + sign;
        log.info("{}请求删除文件: {}", admin.getNickName(), url);
        log.info("{}删除文件: {}", admin.getNickName(), deleteFileStr);

        ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.DELETE, null, String.class);
        if (!responseEntity.getStatusCode().equals(HttpStatus.OK)) {
            JSONObject jsonObject = JSON.parseObject(responseEntity.getBody());
            throw new CustomParameterizedException(jsonObject.getJSONObject("parameters").getString("message"));
        }
    }

    /**
     * 创建文件
     *
     * @param admin
     * @param itemId
     * @param serverId
     * @param fileMakeDTO
     */
    public void mkdir(Admin admin, Integer itemId, Integer serverId, FileMakeDTO fileMakeDTO) {
        ServerInfo serverInfo = serverInfoService.get(serverId);
        itemServerPathService.hasAuthThrow(admin, itemId, serverId, fileMakeDTO.getPath());

        Long timestamp = System.currentTimeMillis();
        String sign = SignUtil.sign(fileMakeDTO, timestamp);
        String url = "http://" + serverInfo.getIp() + ":" + filePort + fileContextPath + "/files/mkdir?timestamp=" + timestamp + "&sign=" + sign;
        log.info("{}请求创建文件夹: {}", admin.getNickName(), url);
        log.info("{}创建文件目录: {},文件夹名称:{}", admin.getNickName(), fileMakeDTO.getPath(), fileMakeDTO.getNames().stream().collect(Collectors.joining(",")));
        try {
            RequestEntity<FileMakeDTO> requestEntity = RequestEntity.put(new URI(url)).header("Content-Type", "application/json").body(fileMakeDTO);
            ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);
            if (!responseEntity.getStatusCode().equals(HttpStatus.OK)) {
                JSONObject jsonObject = JSON.parseObject(responseEntity.getBody());
                throw new CustomParameterizedException(jsonObject.getJSONObject("parameters").getString("message"));
            }
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }

    }

    /**
     * 压缩文件
     *
     * @param admin
     * @param itemId
     * @param serverId
     * @param compressDTO
     */
    public void compress(Admin admin, Integer itemId, Integer serverId, CompressDTO compressDTO) {
        ServerInfo serverInfo = serverInfoService.get(serverId);
        //权限
        compressDTO.getFiles().forEach(file -> {
            itemServerPathService.hasAuthThrow(admin, itemId, serverId, file);
        });
        itemServerPathService.hasAuthThrow(admin, itemId, serverId, compressDTO.getDestFile());

        Long timestamp = System.currentTimeMillis();
        String sign = SignUtil.sign(compressDTO, timestamp);
        String url = "http://" + serverInfo.getIp() + ":" + filePort + fileContextPath + "/compress?timestamp=" + timestamp + "&sign=" + sign;
        log.info("{}请求压缩文件: {}", admin.getNickName(), url);
        log.info("{}把{}压缩文件到 {}", admin.getNickName(), compressDTO.getFiles(), compressDTO.getDestFile());
        try {
            RequestEntity<CompressDTO> requestEntity = RequestEntity.put(new URI(url)).header("Content-Type", "application/json").body(compressDTO);
            ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);
            if (!responseEntity.getStatusCode().equals(HttpStatus.OK)) {
                JSONObject jsonObject = JSON.parseObject(responseEntity.getBody());
                throw new CustomParameterizedException(jsonObject.getJSONObject("parameters").getString("message"));
            }
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }
    }

    /**
     * 解压文件
     *
     * @param admin
     * @param itemId
     * @param serverId
     * @param decompressDTO
     */
    public void decompress(Admin admin, Integer itemId, Integer serverId, DecompressDTO decompressDTO) {
        ServerInfo serverInfo = serverInfoService.get(serverId);
        //权限
        itemServerPathService.hasAuthThrow(admin, itemId, serverId, decompressDTO.getDestPath());
        itemServerPathService.hasAuthThrow(admin, itemId, serverId, decompressDTO.getSourceFile());

        Long timestamp = System.currentTimeMillis();
        String sign = SignUtil.sign(decompressDTO, timestamp);
        String url = "http://" + serverInfo.getIp() + ":" + filePort + fileContextPath + "/decompress?timestamp=" + timestamp + "&sign=" + sign;
        log.info("{}请求解压文件: {}", admin.getNickName(), url);
        log.info("{}把{}解压到 {}", admin.getNickName(), decompressDTO.getSourceFile(), decompressDTO.getDestPath());
        try {
            RequestEntity<DecompressDTO> requestEntity = RequestEntity.put(new URI(url)).header("Content-Type", "application/json").body(decompressDTO);
            ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);
            if (!responseEntity.getStatusCode().equals(HttpStatus.OK)) {
                JSONObject jsonObject = JSON.parseObject(responseEntity.getBody());
                throw new CustomParameterizedException(jsonObject.getJSONObject("parameters").getString("message"));
            }
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }
    }
}
